#include <falso_jni/FalsoJNI_Impl.h>
#include <falso_jni/FalsoJNI.h>
#include "utils/logger.h"
#include "reimpl/io.h"
#include <dirent.h>
#include <main.h>
/*
 * JNI Methods
*/

// jlong GetCurrentTime(jmethodID id, va_list args) {
//     int time=current_timestamp_ms();
//     debugPrintf("GetCurrentTime(%d)",time);
//     return (int64_t) time;
// }

jlong GetCurrentTime(jmethodID id, va_list args) {
    return (int64_t) current_timestamp_ms();
}

jlong OnGetAvailableSpace(jmethodID id, va_list args) {

    debugPrint("OnGetAvailableSpace(10000000000)");
    return 10000000000;
}

void OnDestroy(jmethodID id, va_list args) {
    debugPrint("OnDestroy() requested via JNI.");
    exit(0);
}

void OnSetTimer(jmethodID id, va_list args) {
    uint32_t Sleeptime = va_arg(args, int);
    debugPrintf("OnSetTimer(%d)",Sleeptime);
    SetSleepTime(Sleeptime);
}

jobject OnLoadFile(jmethodID id, va_list args) {
    const char * value = va_arg(args, char*);
    int type = va_arg(args, int);
    debugPrint("OnLoadFile(%s,%d)",value,type);
    int num;
    // jintArray JintArray=NewCharArray(&jni,num,"DeviceInfo",NULL);
    // for (size_t i = 0; i < num; i++)
    // {
    //     SetObjectArrayElement(&jni,JintArray,i,i);
    // }
    return (jobject)getData(value,&num);
}

void OnSaveFile(jmethodID id, va_list args) {

    debugPrint("OnSaveFile()");
}

jint GetTextHeight(jmethodID id, va_list args) {
    debugPrintf("GetTextHeight(20)");
    return 20;
}

jint existsInAsset(jmethodID id, va_list args) {
    const char * value = va_arg(args, char*);
    char fopen_path_real[256];
    memset(fopen_path_real,0,256);
    sceClibSnprintf(fopen_path_real, sizeof(fopen_path_real), "ux0:data/MapleLive/%s", value);
    debugPrint("existsInAsset(%s)",fopen_path_real);
    return file_exists(fopen_path_real);
}

jint GetTextWidth(jmethodID id, va_list args) {
    const char * value = va_arg(args, char*);
    //debugPrintf("GetTextWidth(%s)",value);
    return 20*strlen(value);
}

jobject GetTextTexture(jmethodID id, va_list args) {
    const char* value = va_arg(args, char*);
    int style = va_arg(args, int);
    int color1 = va_arg(args, int);
    int color2 = va_arg(args, int);
    
    debugPrint("GetTextTexture(%s,%d,%d,%d)",value,style,color1,color2);
    return NULL;
}

jintArray readFileList(char *basePath)
{
    DIR *dir;
    struct dirent *ptr;
    char base[1000];

    if ((dir=opendir(basePath)) == NULL)
    {
        // perror("Open dir error...");
        // exit(1);
        debugPrint("getFilesInDir(%s) return null",basePath);
        return NULL;
    }
    int num=0;
    while ((ptr=readdir(dir)) != NULL)
    {
        if(strcmp(ptr->d_name,".")==0 || strcmp(ptr->d_name,"..")==0)    ///current dir OR parrent dir
            continue;
        
        // else if(ptr->d_type == 8)    ///file
        //     printf("d_name:%s/%s\n",basePath,ptr->d_name);
        // else if(ptr->d_type == 10)    ///link file
        //     printf("d_name:%s/%s\n",basePath,ptr->d_name);
        // else if(ptr->d_type == 4)    ///dir
        // {
        //     memset(base,'\0',sizeof(base));
        //     strcpy(base,basePath);
        //     strcat(base,"/");
        //     strcat(base,ptr->d_name);
        //     readFileList(base);
        // }
        num++;
    }

    jintArray JintArray=NewIntArray(&jni,num,"DeviceInfo",NULL);
    for (size_t i = 0; i < num; i++)
    {
        SetObjectArrayElement(&jni,JintArray,i,i);
    }
    debugPrint("getFilesInDir(%s) return %d",basePath,num);
    closedir(dir);
    return JintArray;
}

jobject getFilesInDir(jmethodID id, va_list args) {
    const char * value = va_arg(args, char*);
    char fopen_path_real[256];
    memset(fopen_path_real,0,256);
    //"assets_ios/"
    sceClibSnprintf(fopen_path_real, sizeof(fopen_path_real), "ux0:data/MapleLive/%s", value+11);

    //debugPrintf("getFilesInDir(%s)",fopen_path_real);
    return readFileList(fopen_path_real);
    //return NULL;
}

jint GetAppTypeVersion()
{
    debugPrintf("GetAppTypeVersion(3)");
    return 3;
}

int size=0;
void SetTextSize(jmethodID id, va_list args) {
    size = va_arg(args, int);
    debugPrintf("SetTextSize(%d)",size);
}

void removeFileInDir(jmethodID id, va_list args) {
    const char * value = va_arg(args, char*);
    debugPrint("removeFileInDir(%s)",value);
}

void startSound(jmethodID id, va_list args) {
    debugPrintf("startSound()");
}

void startMusic(jmethodID id, va_list args) {
    debugPrintf("startMusic()");
}

void stopSound(jmethodID id, va_list args) {
    debugPrintf("stopSound()");
}
void reloadSound(jmethodID id, va_list args) {
    debugPrintf("reloadSound()");
}

void playVibrate(jmethodID id, va_list args) {
    debugPrintf("playVibrate()");
}

void OnOpenProgressbar(jmethodID id, va_list args) {
    debugPrint("OnOpenProgressbar()");
}
void OnOpenInfo(jmethodID id, va_list args) {
    const char * value = va_arg(args, char*);
    debugPrint("OnOpenInfo(%s)",value);
}
void OnCloseProgressbar(jmethodID id, va_list args) {
    debugPrint("OnCloseProgressbar()");
}
void OnOpenHelp(jmethodID id, va_list args) {
    const char * value = va_arg(args, char*);
    debugPrint("OnOpenHelp(%s)",value);
}
void OnOpenNetConnect(jmethodID id, va_list args) {
    debugPrint("OnOpenNetConnect()");
}

void OnCloseNetConnect(jmethodID id, va_list args) {
    debugPrint("OnCloseNetConnect()");
}

void OnOpenPurchase(jmethodID id, va_list args) {
    debugPrint("OnOpenPurchase()");
}

jobject getRunProcessInfo(jmethodID id, va_list args) {
    debugPrint("getRunProcessInfo(com.nexonmobile.maplelive.googleplay)");
    char* Info[]={"com.nexonmobile.maplelive.googleplay"};
    return Info;
}

jobject GetRealDeviceMacAddress(jmethodID id, va_list args) {
    debugPrintf("GetRealDeviceMacAddress(02:00:00:00:00:00)");
    return "02:00:00:00:00:00";
}

void FileSaveDB(jmethodID id, va_list args) {
    const char* value = va_arg(args, char*);
    debugPrint("FileSaveDB(%s)",value);
}

void callHttpCheatProcess(jmethodID id, va_list args)
{
    debugPrintf("callHttpCheatProcess()");
}

void MakeDir(jmethodID id, va_list args)
{
    const char* value = va_arg(args, char*);
    debugPrint("MakeDir(%s)",value);
}

NameToMethodID nameToMethodId[] = {
    { 1, "OnDestroy", METHOD_TYPE_VOID ,OnDestroy}, // ()V
    { 2, "OnSetTimer", METHOD_TYPE_VOID ,OnSetTimer}, // (I)V
    { 3, "OnLoadFile", METHOD_TYPE_OBJECT ,OnLoadFile}, // ()I
    { 4, "OnSaveFile", METHOD_TYPE_VOID ,OnSaveFile}, // ()V
    { 5, "OnGetAvailableSpace", METHOD_TYPE_INT,NULL }, // ()I
    { 6, "removeFileInDir", METHOD_TYPE_VOID ,removeFileInDir}, // (I)V
    { 7, "getFilesInDir", METHOD_TYPE_INT ,getFilesInDir}, // ()I
    { 8, "existsInAsset", METHOD_TYPE_VOID ,existsInAsset}, // (I)V
    { 9, "startSound", METHOD_TYPE_VOID ,startSound}, // (I)V
    { 10, "startMusic", METHOD_TYPE_LONG ,startMusic}, // ()J
    { 11, "stopSound", METHOD_TYPE_INT,stopSound }, // ()I
    { 12, "playVibrate", METHOD_TYPE_VOID ,playVibrate}, // (Ljava/lang/String;)V
    { 13, "reloadSound", METHOD_TYPE_OBJECT ,reloadSound}, // ()Ljava/lang/String;
    { 14, "OnOpenInfo", METHOD_TYPE_OBJECT,OnOpenInfo }, // ()Ljava/lang/String;
    { 15, "OnOpenProgressbar", METHOD_TYPE_OBJECT ,OnOpenProgressbar}, // ()Ljava/lang/String;
    { 16, "OnCloseProgressbar", METHOD_TYPE_FLOAT ,OnCloseProgressbar}, // ()F
    { 17, "OnOpenNetConnect", METHOD_TYPE_OBJECT ,OnOpenNetConnect}, // ()Ljava/lang/String;
    { 18, "OnCloseNetConnect", METHOD_TYPE_VOID,OnCloseNetConnect }, // (I)V
    { 19, "OnOpenPurchase", METHOD_TYPE_INT,OnOpenPurchase }, // ()I
    { 20, "getRunProcessInfo", METHOD_TYPE_VOID,getRunProcessInfo }, // ()V
    { 21, "setTextField", METHOD_TYPE_VOID ,NULL}, // ()V
    { 22, "setTextFieldText", METHOD_TYPE_OBJECT ,NULL}, // (IIIIII)V
    { 23, "hidingTextField", METHOD_TYPE_INT ,NULL}, // (III)I
    { 24, "resignTextFieldKeyboard", METHOD_TYPE_VOID,NULL }, // ()V
    { 25, "removeTextField", METHOD_TYPE_VOID ,NULL}, // ()V
    { 26, "setTextView", METHOD_TYPE_VOID ,NULL}, // ()V
    { 27, "setTextViewText", METHOD_TYPE_VOID ,NULL}, // ()V
    { 28, "setLengthViewPos", METHOD_TYPE_INT ,NULL}, // ([BII)I
    { 29, "hidingTextView", METHOD_TYPE_INT ,NULL}, // ([BII)I
    { 30, "resignTextViewKeyboard", METHOD_TYPE_INT ,NULL}, // ([BII)I
    { 31, "removeTextView", METHOD_TYPE_INT ,NULL}, // ([BII)I
    { 32, "setClauseView", METHOD_TYPE_INT ,NULL}, // ([BII)I
    { 33, "removeClauseView", METHOD_TYPE_INT ,NULL}, // ([BII)I
    { 34, "getNetState", METHOD_TYPE_INT ,NULL}, // ([BII)I
    { 35, "callHttpCheatProcess", METHOD_TYPE_INT ,callHttpCheatProcess}, // ([BII)I
    { 36, "callAdenAppHttp", METHOD_TYPE_INT,NULL }, // ([BII)I
    { 37, "isNickNameRegularExpressionSearch", METHOD_TYPE_INT ,NULL}, // ([BII)I
    { 38, "addWebView", METHOD_TYPE_INT ,NULL}, // ([BII)I
    { 39, "GetRealDeviceMacAddress", METHOD_TYPE_INT,GetRealDeviceMacAddress }, // ([BII)I
    { 40, "FileSaveDB", METHOD_TYPE_INT ,FileSaveDB}, // ([BII)I
    { 41, "FileExistsDB", METHOD_TYPE_INT ,NULL}, // ([BII)I
    { 42, "FileLoadDB", METHOD_TYPE_INT ,NULL}, // ([BII)I
    { 43, "GetTextTexture", METHOD_TYPE_INT ,GetTextTexture}, // ([BII)I
    { 44, "GetTextHeight", METHOD_TYPE_INT ,GetTextHeight}, // ([BII)I
    { 45, "GetTextWidth", METHOD_TYPE_INT ,GetTextWidth}, // ([BII)I
    { 46, "SetTextSize", METHOD_TYPE_INT ,SetTextSize}, // ([BII)I
    { 47, "GetCurrentTime", METHOD_TYPE_LONG ,NULL}, // ([BII)I
    { 48, "OnOpenHelp", METHOD_TYPE_INT ,OnOpenHelp}, // ([BII)I
    { 49, "GetAppTypeVersion", METHOD_TYPE_INT ,GetAppTypeVersion}, // ([BII)I
    { 50, "MakeDir", METHOD_TYPE_INT ,MakeDir}, // ([BII)I
};

MethodsBoolean methodsBoolean[] = {};
MethodsByte methodsByte[] = {};
MethodsChar methodsChar[] = {};
MethodsDouble methodsDouble[] = {

};
MethodsFloat methodsFloat[] = {

};
MethodsInt methodsInt[] = {};
MethodsLong methodsLong[] = {
    {47,GetCurrentTime},
    {5,OnGetAvailableSpace}
};
MethodsObject methodsObject[] = {};
MethodsShort methodsShort[] = {};
MethodsVoid methodsVoid[] = {};

/*
 * JNI Fields
*/

// System-wide constant that applications sometimes request
// https://developer.android.com/reference/android/content/Context.html#WINDOW_SERVICE
char WINDOW_SERVICE[] = "window";

// System-wide constant that's often used to determine Android version
// https://developer.android.com/reference/android/os/Build.VERSION.html#SDK_INT
// Possible values: https://developer.android.com/reference/android/os/Build.VERSION_CODES
const int SDK_INT = 19; // Android 4.4 / KitKat

NameToFieldID nameToFieldId[] = {
		{ 0, "WINDOW_SERVICE", FIELD_TYPE_OBJECT }, 
		{ 1, "SDK_INT", FIELD_TYPE_INT },
};

FieldsBoolean fieldsBoolean[] = {};
FieldsByte fieldsByte[] = {};
FieldsChar fieldsChar[] = {};
FieldsDouble fieldsDouble[] = {};
FieldsFloat fieldsFloat[] = {};
FieldsInt fieldsInt[] = {
		{ 1, SDK_INT },
};
FieldsObject fieldsObject[] = {
		{ 0, WINDOW_SERVICE },
};
FieldsLong fieldsLong[] = {};
FieldsShort fieldsShort[] = {};

__FALSOJNI_IMPL_CONTAINER_SIZES
